module BranchJumpUnit (
    input   logic [63:0]    pc,
    input   logic [63:0]    rs1,
    input   logic [63:0]    rs2,
    input   logic [63:0]    imm,
    input   logic [7:0]     bj_info,
    output  logic           bj_flag,
    output  logic [63:0]    bj_target
);

/* ------------ branch jump inst ------------ */
    wire inst_beq   = bj_info[0];
    wire inst_bne   = bj_info[1];
    wire inst_blt   = bj_info[2];
    wire inst_bge   = bj_info[3];
    wire inst_bltu  = bj_info[4];
    wire inst_bgeu  = bj_info[5];
    wire inst_jal   = bj_info[6];
    wire inst_jalr  = bj_info[7];
/* ------------ branch jump inst ------------ */


/* ------------------------ branch jump compare ------------------------ */
    logic [63:0]    bj_sum;
    logic           bj_cout;

    wire [63:0] not_rs2 = ~rs2;
    /* verilator lint_off WIDTH */
    assign {bj_cout, bj_sum} = rs1 + not_rs2 + 1'b1;


    wire eq = (bj_cout) & (~|bj_sum);
    wire ne = ~eq;
    wire lt = (rs1[63]              & ~rs2[63]) |
              ((rs1[63] ~^ rs2[63]) & bj_sum[63]);
    wire ltu = ~bj_cout;
    wire ge  = ~lt;
    wire geu = bj_cout;
/* ------------------------ branch jump compare ------------------------ */


    // branch jump target
    /* verilator lint_off WIDTH */
    assign bj_target = (inst_jalr ? rs1 : pc) + imm;

    // branch jump flag
    assign bj_flag = (inst_beq  & eq ) 
                   | (inst_bne  & ne ) 
                   | (inst_blt  & lt ) 
                   | (inst_bge  & ge ) 
                   | (inst_bltu & ltu) 
                   | (inst_bgeu & geu) 
                   | (inst_jal       ) 
                   | (inst_jalr      );
endmodule
